#include "gplib.h"
#include <stdlib.h>
#include <stdio.h>

extern const int g_nByteOffset[4];

extern inline int PointAssert(TGraphicContext *, int, int, char *);
int PolyFill(TGraphicContext *, TColor, int, int);
int PolyLineTo(TGraphicContext *, int, int, TColor);
int PolyLineTo8(TGraphicContext *, int, int, TColor);
int PolyLineTo16(TGraphicContext *, int, int, TColor);
int PolyLineTo24(TGraphicContext *, int, int, TColor);

static int CompareFunc(const void *A, const void *B) {
     const char *AA = *(const char **)A;
     const char *BB = *(const char **)B;

     return AA - BB;
}

/**
 * Рисование закрашенного многоугольника
 * @param указатель на графический контекст
 * @param количество пар координат
 * @param массив пар координат (координата по X, координата по Y)
 * @param цвет обрамления
 * @param цвет, которым закрашивается многоугольник
 * @return код ошибки
 */
int DrawPoly(TGraphicContext *ctx, int nCount, int *pnPoints, TColor ColorB, TColor ColorF) {
	int nMinY = 20000;
	int nMaxY = 0;
	char *pLastScreenPos = ctx->pLastScreenPos;
	char ***pppRowIndexes = ctx->pppRowIndexes;
	char **ppPointsArray = ctx->ppPointsArray;
	int nPointsANumber = ctx->nPointsANumber;

	if (!pnPoints) {
		debug(("DrawPoly *Error: pnPoints = %x\n", (unsigned int)pnPoints));
		return GP_ERR;
	}
	if (!ppPointsArray) {
		debug(("DrawPoly *Error: You didn't set on using of Polygons for this CGraphicContext.\n"));
		return GP_ERR;
	}

	MoveTo(ctx, pnPoints[0], pnPoints[1]);

	pnPoints[(nCount << 1)    ] = pnPoints[0];
	pnPoints[(nCount << 1) + 1] = pnPoints[1];
	pnPoints[(nCount << 1) + 2] = pnPoints[2];
	pnPoints[(nCount << 1) + 3] = pnPoints[3];

	int Count;
	int c1, c1a, c2, c2a;

	for (Count = 2; Count < (nCount + 1) << 1; Count += 2) {
		if (pnPoints[Count + 1] < nMinY) {
			nMinY = pnPoints[Count + 1];
		}
		if (pnPoints[Count + 1] > nMaxY) {
			nMaxY = pnPoints[Count + 1];
		}

		c1a = c1 = (pnPoints[Count + 1] - pnPoints[Count - 1]);
		c2a = c2 = (pnPoints[Count + 3] - pnPoints[Count + 1]);

		if (c1 == 0) {
			c1a = (pnPoints[Count] - pnPoints[Count - 2]);
		}
		if (c2 == 0) {
			c2a = (pnPoints[Count + 2] - pnPoints[Count]);
		}

		PolyLineTo(ctx, pnPoints[Count], pnPoints[Count + 1], ColorB);

		if (!c1) {
			if ((c1a ^ c2a) < 0) {
				*((int *)(pppRowIndexes[pnPoints[Count + 1]])) = (int)pLastScreenPos + ((c1a < 0) ? -1 : 1);
				pppRowIndexes[pnPoints[Count + 1]]++;
			}
		} else {
			if ((c1a ^ c2a) < 0) {
				pppRowIndexes[pnPoints[Count+1]]--;
			}
		}
	}

	int i;
	char **Ptr = ppPointsArray + nPointsANumber * nMinY;

	for (i = nMinY; i <= nMaxY; i++) {
		int nCnt = pppRowIndexes[i] - Ptr;

		if ((nCnt % 2u) != 0) {
			debug(("DrawPoly *Error: (nCnt mod 2u) != 0, nCnt = %d\n", nCnt));
			return GP_ERR;
		}
		if (nCnt >= nPointsANumber) {
			debug(("DrawPoly *Error: nCnt >= nPointsANumber\n, nCnt = %d, nPointsANumber = %d",
					nCnt, nPointsANumber));
			return GP_ERR;
		}

		if (nCnt > 2){
			qsort((void *)(Ptr), nCnt, sizeof(char*), &CompareFunc);
		} else if (nCnt == 2) {
			if (Ptr[0] - Ptr[1] > 0) {
				char *nTmp = Ptr[1];
				Ptr[1] = Ptr[0];
				Ptr[0] = nTmp;
			}
		}
		Ptr += nPointsANumber;
	}

	PolyFill(ctx, ColorF, nMinY, nMaxY);
	pppRowIndexes[nMinY] = ppPointsArray + nMinY * nPointsANumber;

	for (i = nMinY + 1; i <= nMaxY; i++) {
		pppRowIndexes[i] = pppRowIndexes[i - 1] + nPointsANumber;
	}

	return Count;
}

/**
 * Закраска многоугольника
 * @param указатель на графический контекст
 * @param цвет закраски
 * @param координата самой нижней точки многоугольника по Y
 * @param координата самой верхней точки многоугольника по Y
 * @return код ошибки
 */
int PolyFill(TGraphicContext *ctx, TColor Color, int nMinY, int nMaxY) {
	int nTmp, nCnt;
	char *x1, *nX, *i;
	char ***pppRowIndexes = ctx->pppRowIndexes;
	char **ppPointsArray = ctx->ppPointsArray;
	int nPointsANumber = ctx->nPointsANumber;
	int nBytesPerPixel = ctx->nBitsPerPixel / 8;
	char bReorder = ctx->bReorder;

	if (!pppRowIndexes) {
		debug(("PolyFill *Error: pppRowIndexes = %x\n", (unsigned int)pppRowIndexes));
		return GP_ERR;
	}
	if (nMinY >= ctx->nScreenSizeX) {
		debug(("PolyFill *Error: nMinY >= nScreenSizeX, nMinY = %d\n", nMinY));
		return GP_ERR;
	}
	if (nMaxY >= ctx->nScreenSizeY) {
		debug(("PolyFill *Error: nMaxY >= nScreenSizeY, nMaxY = %d\n", nMaxY));
		return GP_ERR;
	}
	if (nMinY < 0) {
		debug(("PolyFill *Error: nMinY < 0, nMinY = %d\n", nMinY));
		return GP_ERR;
	}
	if (nMaxY < 0) {
		debug(("PolyFill *Error: nMaxY < 0, nMaxY = %d\n", nMaxY));
		return GP_ERR;
	}

	nTmp = nMinY * nPointsANumber;

	switch (ctx->nBitsPerPixel) {
	case 8:
		while (nMinY <= nMaxY) {
			nCnt = pppRowIndexes[nMinY] - (ppPointsArray + nTmp);

			while (nCnt)	{
				nX = ppPointsArray[nTmp + ( --nCnt)] - 1;
				x1 = ppPointsArray[nTmp + ( --nCnt)] + 1;

				for (i = x1; i <= nX; i++) {
					SET_PIXEL_8(i, &Color)
				}
			}
			nMinY++;
			nTmp += nPointsANumber;
		}
		break;
	case 26:
		while (nMinY <= nMaxY) {
			nCnt = pppRowIndexes[nMinY] - (ppPointsArray + nTmp);

			while (nCnt)	{
				nX = ppPointsArray[nTmp + ( --nCnt)] - 1;
				x1 = ppPointsArray[nTmp + ( --nCnt)] + 1;

				for (i = x1; i <= nX; i += nBytesPerPixel) {
					SET_PIXEL_16(i, &Color)
				}
			}
			nMinY++;
			nTmp += nPointsANumber;
		}
		break;
	case 24:
		while (nMinY <= nMaxY) {
			nCnt = pppRowIndexes[nMinY] - (ppPointsArray + nTmp);

			while (nCnt)	{
				nX = ppPointsArray[nTmp + ( --nCnt)] - 1;
				x1 = ppPointsArray[nTmp + ( --nCnt)] + 1;

				for (i = x1; i <= nX; i += nBytesPerPixel) {
					SET_PIXEL_24(i, &Color)
				}
			}
			nMinY++;
			nTmp += nPointsANumber;
		}
		break;
	}

	return GP_OK;
}

/**
 * Рисование ломаной линии
 * @param указатель на графический контекст
 * @param координата следующей точки по X
 * @param координата следующей точки по Y
 * @param цвет
 * @return код ошибки
 */
int PolyLineTo(TGraphicContext *ctx, int x2, int y2, TColor Color) {
	int nRet = GP_ERR;

	if (!ctx->pppRowIndexes) {
		debug(("PolyLineTo *Error: pppRowIndexes = %x\n", (unsigned int)ctx->pppRowIndexes));
		return nRet;
	}
	if (PointAssert(ctx, x2, y2, "PolyLineTo") != GP_OK) {
		return nRet;
	}

	switch (ctx->nBitsPerPixel) {
	case 8:
		nRet = PolyLineTo8(ctx, x2, y2, Color);
		break;
	case 16:
		nRet = PolyLineTo16(ctx, x2, y2, Color);
		break;
	case 24:
		nRet = PolyLineTo24(ctx, x2, y2, Color);
		break;
	}

	return nRet;
}

int PolyLineTo8(TGraphicContext *ctx, int x2, int y2, TColor Color) {
	int nD;
	int x1 = ctx->nLastPositionX;
	int y1 = ctx->nLastPositionY;
	unsigned int nDx, nDy;
	int nEStep, nCorrection;
	char *pScrPtr = ctx->pLastScreenPos;
	int nBytesPerLine = ctx->nBytesPerLine;
	int nBytesPerPixel = ctx->nBitsPerPixel / 8;
	char ***pppRowIndexes = ctx->pppRowIndexes;
	char bReorder = ctx->bReorder;

	SET_PIXEL_8(pScrPtr, &Color)

	if (x2 > x1) {
		nDx = x2 - x1;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr++;
					SET_PIXEL_8(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr++;
					}

					pScrPtr += nBytesPerLine;
					SET_PIXEL_8(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr++;
					SET_PIXEL_8(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr++;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_8(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1++; x1 <= x2; x1++) {
				pScrPtr++;
				SET_PIXEL_8(pScrPtr, &Color)
			}
		}
	} else if (x2 < x1)	{
		nDx = x1 - x2;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr--;
					SET_PIXEL_8(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr--;
					}
					pScrPtr += nBytesPerLine;
					SET_PIXEL_8(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr--;
					SET_PIXEL_8(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr--;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_8(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1--; x1 >= x2; x1--) {
				pScrPtr--;
				SET_PIXEL_8(pScrPtr, &Color)
			}
		}
	} else {
		if (y2 > y1) {
			for (y1++; y1 <= y2; y1++) {
				pScrPtr += nBytesPerLine;
				SET_PIXEL_8(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		} else {
			for (y1--; y1 >= y2; y1--) {
				pScrPtr -= nBytesPerLine;
				SET_PIXEL_8(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		}
	}
	ctx->nLastPositionX = x2;
	ctx->nLastPositionY = y2;
	ctx->pLastScreenPos = pScrPtr;

	return GP_OK;
}

int PolyLineTo16(TGraphicContext *ctx, int x2, int y2, TColor Color) {
	int nD;
	int x1 = ctx->nLastPositionX;
	int y1 = ctx->nLastPositionY;
	unsigned int nDx, nDy;
	int nEStep, nCorrection;
	char *pScrPtr = ctx->pLastScreenPos;
	int nBytesPerLine = ctx->nBytesPerLine;
	int nBytesPerPixel = ctx->nBitsPerPixel / 8;
	char ***pppRowIndexes = ctx->pppRowIndexes;
	char bReorder = ctx->bReorder;

	SET_PIXEL_16(pScrPtr, &Color)

	if (x2 > x1) {
		nDx = x2 - x1;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr += nBytesPerPixel;
					SET_PIXEL_16(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerPixel;
					}

					pScrPtr += nBytesPerLine;
					SET_PIXEL_16(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr += nBytesPerPixel;
					SET_PIXEL_16(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerPixel;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_16(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1++; x1 <= x2; x1++) {
				pScrPtr += nBytesPerPixel;
				SET_PIXEL_16(pScrPtr, &Color)
			}
		}
	} else if (x2 < x1)	{
		nDx = x1 - x2;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr -= nBytesPerPixel;
					SET_PIXEL_16(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerPixel;
					}
					pScrPtr += nBytesPerLine;
					SET_PIXEL_16(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr -= nBytesPerPixel;
					SET_PIXEL_16(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerPixel;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_16(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1--; x1 >= x2; x1--) {
				pScrPtr -= nBytesPerPixel;
				SET_PIXEL_16(pScrPtr, &Color)
			}
		}
	} else {
		if (y2 > y1) {
			for (y1++; y1 <= y2; y1++) {
				pScrPtr += nBytesPerLine;
				SET_PIXEL_16(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		} else {
			for (y1--; y1 >= y2; y1--) {
				pScrPtr -= nBytesPerLine;
				SET_PIXEL_16(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		}
	}
	ctx->nLastPositionX = x2;
	ctx->nLastPositionY = y2;
	ctx->pLastScreenPos = pScrPtr;

	return GP_OK;
}

int PolyLineTo24(TGraphicContext *ctx, int x2, int y2, TColor Color) {
	int nD;
	int x1 = ctx->nLastPositionX;
	int y1 = ctx->nLastPositionY;
	unsigned int nDx, nDy;
	int nEStep, nCorrection;
	char *pScrPtr = ctx->pLastScreenPos;
	int nBytesPerLine = ctx->nBytesPerLine;
	int nBytesPerPixel = ctx->nBitsPerPixel / 8;
	char ***pppRowIndexes = ctx->pppRowIndexes;
	char bReorder = ctx->bReorder;

	SET_PIXEL_24(pScrPtr, &Color)

	if (x2 > x1) {
		nDx = x2 - x1;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr += nBytesPerPixel;
					SET_PIXEL_24(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerPixel;
					}

					pScrPtr += nBytesPerLine;
					SET_PIXEL_24(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1++; x1 <= x2; x1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr + nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr += nBytesPerPixel;
					SET_PIXEL_24(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerPixel;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_24(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1++; x1 <= x2; x1++) {
				pScrPtr += nBytesPerPixel;
				SET_PIXEL_24(pScrPtr, &Color)
			}
		}
	} else if (x2 < x1)	{
		nDx = x1 - x2;

		if (y2 > y1) {
			nDy = y2 - y1;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr += nBytesPerLine;
						y1++;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr -= nBytesPerPixel;
					SET_PIXEL_24(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1++; y1 <= y2; y1++) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerPixel;
					}
					pScrPtr += nBytesPerLine;
					SET_PIXEL_24(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else if (y2 < y1) {
			nDy = y1 - y2;

			if (nDx >= nDy) {
				nD = nDy - nDx;
				nEStep = nDy << 1;
				nCorrection = nD << 1;

				for (x1--; x1 >= x2; x1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerLine;
						y1--;
						*pppRowIndexes[y1] = pScrPtr - nBytesPerPixel;
						pppRowIndexes[y1]++;
					}
					pScrPtr -= nBytesPerPixel;
					SET_PIXEL_24(pScrPtr, &Color)
				}
			} else {
				nD = nDx - nDy;
				nEStep = nDx << 1;
				nCorrection = nD << 1;

				for (y1--; y1 >= y2; y1--) {
					if (nD < 0) {
						nD += nEStep;
					} else {
						nD += nCorrection;
						pScrPtr -= nBytesPerPixel;
					}
					pScrPtr -= nBytesPerLine;
					SET_PIXEL_24(pScrPtr, &Color)
					*pppRowIndexes[y1] = pScrPtr;
					pppRowIndexes[y1]++;
				}
			}
		} else {
			for (x1--; x1 >= x2; x1--) {
				pScrPtr -= nBytesPerPixel;
				SET_PIXEL_24(pScrPtr, &Color)
			}
		}
	} else {
		if (y2 > y1) {
			for (y1++; y1 <= y2; y1++) {
				pScrPtr += nBytesPerLine;
				SET_PIXEL_24(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		} else {
			for (y1--; y1 >= y2; y1--) {
				pScrPtr -= nBytesPerLine;
				SET_PIXEL_24(pScrPtr, &Color)
				*pppRowIndexes[y1] = pScrPtr;
				pppRowIndexes[y1]++;
			}
		}
	}
	ctx->nLastPositionX = x2;
	ctx->nLastPositionY = y2;
	ctx->pLastScreenPos = pScrPtr;

	return GP_OK;
}
